package com.workcell.workdata.im.repository;


import com.workcell.workdata.im.constant.MessageAction;
import com.workcell.workdata.im.constant.MessageState;
import com.workcell.workdata.im.entity.Message;
import com.workcell.workdata.im.entity.MessageIndex;
import com.workcell.workdata.im.repository.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class MessageRepositoryProxy {

    private final EventMessageRepository eventMessageRepository;

    private final ChatMessageRepository chatMessageRepository;

    private final MessageIndexRepository messageIndexRepository;

    private final Map<String, MessageRepository> repositoryMap = new HashMap<>();
    private final Map<String, BaseMessageMapper<? extends Message>> mappingMap = new HashMap<>();

    private final BaseMessageMapper<? extends Message> ignoreMessageMapper = new NoneMessageMapper();


    @Autowired
    public MessageRepositoryProxy(AppMessageRepository appMessageRepository,
                                  ChatMessageRepository chatMessageRepository,
                                  GroupMessageRepository groupMessageRepository,
                                  EventMessageRepository eventMessageRepository,
                                  SystemMessageRepository systemMessageRepository,
                                  MessageIndexRepository messageIndexRepository){
        this.eventMessageRepository = eventMessageRepository;
        this.chatMessageRepository = chatMessageRepository;
        this.messageIndexRepository = messageIndexRepository;

        repositoryMap.put(MessageAction.ACTION_0,chatMessageRepository);
        repositoryMap.put(MessageAction.ACTION_2,systemMessageRepository);
        repositoryMap.put(MessageAction.ACTION_3,groupMessageRepository);
        repositoryMap.put(MessageAction.ACTION_4,groupMessageRepository);
        repositoryMap.put(MessageAction.ACTION_200,appMessageRepository);

        mappingMap.put(MessageAction.ACTION_2,new SystemMessageMapper());
        mappingMap.put(MessageAction.ACTION_3,new GroupMessageMapper());
        mappingMap.put(MessageAction.ACTION_4,new GroupMessageMapper());
        mappingMap.put(MessageAction.ACTION_200,new AppMessageMapper());
    }

    @Async("saveTaskExecutor")
    public void save(Message message){

        Message newMessage = mappingMap.getOrDefault(message.getAction(),ignoreMessageMapper).save(message);

        MessageRepository messageRepository = repositoryMap.getOrDefault(message.getAction(),eventMessageRepository);

        messageRepository.saveAndFlush(newMessage);
    }

    @Async("saveTaskExecutor")
    public void save(List<MessageIndex> indices){
        messageIndexRepository.saveAllAndFlush(indices);
    }


    public void delete(Message message){
        repositoryMap.getOrDefault(message.getAction(),eventMessageRepository).delete(message);
    }

    public Message findOne(Long id,String action) {
        Message message = repositoryMap.getOrDefault(action,eventMessageRepository).findOne(id);
        if (message == null){
            return null;
        }
        return mappingMap.getOrDefault(message.getAction(),ignoreMessageMapper).view(message);
    }

    public List<Message> findList(List<MessageIndex> indices, String action) {

        List<Long> idList = indices.stream().filter(index -> action == null || Objects.equals(action,index.getAction())).map(MessageIndex::getMid).collect(Collectors.toList());

        if (idList.isEmpty()){
            return new LinkedList<>();
        }

        indices.removeIf(index -> Objects.equals(action,index.getAction()));

        List<Message> dataList = repositoryMap.getOrDefault(action,eventMessageRepository).findList(idList.toArray(new Long[0]));

        BaseMessageMapper<? extends Message> messageMapper = mappingMap.getOrDefault(action,ignoreMessageMapper);

        return dataList.stream().map(messageMapper::view).collect(Collectors.toList());
    }

    public void read(Long id) {
        chatMessageRepository.updateState(id, MessageState.STATE_READ);
    }

    public void read(List<Long> idList) {
        chatMessageRepository.updateState(idList, MessageState.STATE_READ);
    }

    public void receive(Long id) {
        chatMessageRepository.updateState(id, MessageState.STATE_RECEIVED);
    }

}
